/**
 * 
 */
package com.ms.game.itembox.db;

import java.util.HashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;

import com.ms.game.db.util.UpdateQueryBuilder;
import com.ms.game.itembox.CrystalChangeWay;
import com.ms.game.itembox.Item;
import com.ms.game.itembox.ItemChangeWay;
import com.ms.game.itembox.container.ItemBasic;
import com.ms.game.itembox.container.ItemCrystalCard;
import com.ms.game.itembox.message.SItemRefineResult;
import com.ms.player.Player;
import com.ms.player.PlayerAttributeType;
import com.ms.player.UpdateAttributeList;
import com.ms.service.error.ErrorCode;
import com.ms.service.module.analysisgroup.AnalysisGroupProcessor;
import com.ms.service.module.datacenterlite.CentralAsyncCommand;
import com.xpec.c4.db.dao.PlayerDAO;
import com.xpec.c4.db.hibernate.manager.HibernateManager;
import com.xpec.c4.game.time.TimeSys;
import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.game.utility.GUIDFactory;
import com.xpec.c4.game.utility.GUIDType;
import com.xpec.c4.message.MessageTypes;
import com.xpec.c4.service.message.MessageAction;
import com.xpec.c4.service.module.common.ItemInfoManager;

/**
 * @author TW15010
 *
 */
public class ItemRefineDCLAsync extends CentralAsyncCommand {
	private static final long serialVersionUID = -6050749076485917827L;

	/** log4j object */
	private static final Log log = LogFactory.getLog(ItemRefineDCLAsync.class);

	// 執行參數 ===================================================

	/** 呼叫這個功能的 module id */
	private String srcModuleId;

	/** 角色 guid */
	private GUID playerId;

	/** 要精煉的道具序號 */
	private String itemSn;

	// 執行後回傳結果 =============================================

	/** 更新過得角色屬性資料 */
	private UpdateAttributeList updateAttributeList = new UpdateAttributeList();

	/** 更新過的道具資料 */
	private Item updateItem;

	/** 執行結果 {@link ErrorCode} */
	private int errorCode;

	@Override
	public void asyncExecute() throws Exception {
		// 載入角色資料
		Player player = PlayerDAO.loadPlayerByGuid(playerId);

		// 角色身上的所有道具
		HashMap<String, PlayerItemModel> itemModelMap = ItemDAO.loadPlayerItems(playerId);
		if (itemModelMap == null) {
			errorCode = ErrorCode.LOAD_ITEM_DATA_FROM_DB_FAIL;
			return;
		}

		// 要精煉的道具
		PlayerItemModel itemModel = itemModelMap.get(itemSn);
		if (itemModel == null) {
			errorCode = ErrorCode.ITEM_NOT_FOUND_FROM_PLAYER;
			return;
		}

		// 遊戲中使用的道具資料
		Item item = new Item(itemModel);

		// 做相關檢查
		int res = refineItemVerify(item, player.getCrystal());
		if (res != ErrorCode.SUCCESS) {
			errorCode = res;
			return;
		}

		// 道具的數據資料
		ItemBasic itemBin = ItemInfoManager.getInstance().getItem(itemModel.getItemId());

		// 精煉需要的數量
		int needCrystal = ItemInfoManager.getInstance().getRefineNeedCrystal(item.getRefineLevel(), itemBin);

		// 初始資料
		int orgCrystal = player.getCrystal();
		int orgLevel = itemModel.getRefineLevel();

		// 扣水晶
		player.setCrystal(orgCrystal - needCrystal);
		updateAttributeList.addUpdateValue(PlayerAttributeType.CRYSTAL, player.getCrystal());

		// 提昇等級
		itemModel.setRefineLevel(orgLevel + 1);
		
		if(itemModel.getRefineLevel() >= itemBin.getRefineCrystalCostList().size()){
			itemModel.setRefineEndTime(TimeSys.currentTimeMills());
		}

		item = new Item(itemModel);
		updateItem = item;

		// 寫入 db
		Session session = HibernateManager.txBegin();

		// 更新水晶數量
		UpdateQueryBuilder builder = new UpdateQueryBuilder();
		builder.setSession(session);
		builder.setTableName("PlayerModel");
		builder.addSetValue("crystal", player.getCrystal());
		builder.setWhereKey("guid", player.getGuid().toString());
		builder.executeQuery();

		// 更新道具資料
		session.saveOrUpdate(itemModel);

		boolean dbProcRes = HibernateManager.txCommitFailRollbackClearSession();
		if (!dbProcRes) {
			errorCode = ErrorCode.DB_OPERATION_FAIL;
			return;
		}

		errorCode = ErrorCode.SUCCESS;

		// 寫 log
		GUID orderId = GUIDFactory.createUUID(GUIDType.TYPE_ITEM);
		saveCrystalLog(orderId, player, needCrystal, orgCrystal);
		saveRefineLog(orderId, player, needCrystal, orgCrystal, orgLevel);
		
		//送給統計
		sendCrystalCardChangeToAnalysis(needCrystal);
	}

	@Override
	public void callBackExecute(Object... userData) throws Exception {
		Player player = (Player) userData[0];

		// 回應錯誤碼給 client
		if (errorCode != ErrorCode.SUCCESS) {
			MessageAction.sendFailResultClientMessage(player.getSessionID(), MessageTypes.S_ITEM_REFINE_RESULT,
					SItemRefineResult.class, errorCode);
			return;
		}

		// 更新到角色身上
		updateAttributeList.applyToPlayer(player);
		player.updateItem(updateItem);
		
		// 更新給 client
		player.sendUpdatedAttrToClient();

		// 回傳結果
		SItemRefineResult result = new SItemRefineResult();
		result.setUpdateItem(updateItem.toClientFormat());
		result.setErrorCode(ErrorCode.SUCCESS);

		MessageAction.sendMessage(player.getSessionID(), MessageTypes.S_ITEM_REFINE_RESULT, result);
	}

	/**
	 * 寫水晶異動 log
	 * 
	 * @param orderId
	 *            訂單 id
	 * @param player
	 *            角色資料
	 * @param needCrystal
	 *            異動的水晶數量
	 * @param orgCrystal
	 *            異動前的水晶數量
	 */
	private void saveCrystalLog(GUID orderId, Player player, int needCrystal, int orgCrystal) {
		PlayerCrystalChangeLogModel log = new PlayerCrystalChangeLogModel();

		log.setOrderId(orderId.toString());
		log.setAccountId(player.getAccountId().toString());
		log.setPlayerId(player.getGuid().toString());
		log.setPlayerName(player.getNameWithNumber());
		log.setModuleId(srcModuleId);

		CrystalChangeWay changeWay = CrystalChangeWay.SUB_REFINE_ITEM;
		log.setChangeWay(changeWay.getId());
		log.setChangeWayDesc(changeWay.getDesc());

		log.setChangeCrystal(needCrystal);
		log.setBeforeCrystal(orgCrystal);
		log.setAfterCrystal(player.getCrystal());

		getCurrentModuleServer().saveDbLog(log);
	}

	/**
	 * 寫入道具精煉 log
	 * 
	 * @param orderId
	 *            訂單 id
	 * @param player
	 *            角色資料
	 * @param needCrystal
	 *            水晶異動量
	 * @param orgCrystal
	 *            異動前的水晶數量
	 * @param orgLevel
	 *            精煉前的道具等級
	 */
	private void saveRefineLog(GUID orderId, Player player, int needCrystal, int orgCrystal, int orgLevel) {
		PlayerItemRefineLogModel log = new PlayerItemRefineLogModel();

		log.setOrderId(orderId.toString());
		log.setAccountId(player.getAccountId().toString());
		log.setPlayerId(player.getGuid().toString());
		log.setPlayerName(player.getNameWithNumber());
		log.setModuleId(srcModuleId);
		log.setItemSn(updateItem.getSn());
		log.setItemId(updateItem.getItemId());

		ItemBasic itemBin = ItemInfoManager.getInstance().getItem(updateItem.getItemId());
		log.setItemName(itemBin.getName());

		log.setChangeCrystal(needCrystal);
		log.setBeforeCrystal(orgCrystal);
		log.setAfterCrystal(player.getCrystal());

		log.setBeforeLevel(orgLevel);
		log.setAfterLevel(updateItem.getRefineLevel());

		getCurrentModuleServer().saveDbLog(log);
	}

	/**
	 * 道具精煉錢的相關數值檢查
	 * 
	 * @param refineItem
	 *            要精煉的道具
	 * @param playerCrystalCount
	 *            身上的水晶數量
	 * @return {@link ErrorCode}
	 */
	public static int refineItemVerify(Item refineItem, int playerCrystalCount) {
		// 取得數據資料
		ItemBasic itemBin = ItemInfoManager.getInstance().getItem(refineItem.getItemId());
		if (itemBin == null) {
			return ErrorCode.ITEM_NOT_FOUND_FROM_BIN;
		}

		// 道具不能精煉
		if (!ItemInfoManager.getInstance().isItemCanRefine(itemBin)) {
			return ErrorCode.ITEM_REFINE_ITEM_CAN_NOT_REFINE;
		}

		// 道具有設定精煉過期時間
		if (ItemInfoManager.getInstance().isRefineTimeExpire(refineItem.getRefineEndTime(), TimeSys.currentTimeMills())) {
			return ErrorCode.ITEM_REFINE_REFINE_TIME_EXPIRE;
		}

		// 已經到達最高等級
		if (refineItem.getRefineLevel() >= itemBin.getRefineCrystalCostList().size()) {
			return ErrorCode.ITEM_REFINE_REACH_MAX_LEVEL;
		}

		// 水晶不夠
		int refineCrystalCost = ItemInfoManager.getInstance().getRefineNeedCrystal(refineItem.getRefineLevel(), itemBin);
		if (playerCrystalCount < refineCrystalCost) {
			return ErrorCode.CRYSTAL_NOT_ENOUGH;
		}

		return ErrorCode.SUCCESS;
	}
	
	/**
	 * 水晶的消耗量以水晶卡(單位1)的物品告訴統計
	 */
	private static void sendCrystalCardChangeToAnalysis(int changeValue){
		if(changeValue > 0){
			AnalysisGroupProcessor.sendItemChangeToAnalysis(ItemChangeWay.SUB_USE_ITEM, ItemCrystalCard.basicUnitItemID, 0, changeValue);
		}
	}

	public GUID getPlayerId() {
		return playerId;
	}

	public void setPlayerId(GUID playerId) {
		this.playerId = playerId;
	}

	public String getItemSn() {
		return itemSn;
	}

	public void setItemSn(String itemSn) {
		this.itemSn = itemSn;
	}

	public UpdateAttributeList getUpdateAttributeList() {
		return updateAttributeList;
	}

	public void setUpdateAttributeList(UpdateAttributeList updateAttributeList) {
		this.updateAttributeList = updateAttributeList;
	}

	public int getErrorCode() {
		return errorCode;
	}

	public void setErrorCode(int errorCode) {
		this.errorCode = errorCode;
	}

	public Item getUpdateItem() {
		return updateItem;
	}

	public void setUpdateItem(Item updateItem) {
		this.updateItem = updateItem;
	}

	public String getSrcModuleId() {
		return srcModuleId;
	}

	public void setSrcModuleId(String srcModuleId) {
		this.srcModuleId = srcModuleId;
	}
}
